﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Input;
using Microsoft.Win32;
using System.Windows;
using System.Xml;
using SHomeWorkshop.LunarConcept.Controls;
using SHomeWorkshop.LunarConcept.ModifingManager;
using System.Windows.Controls;
using System.Windows.Media;
using SHomeWorkshop.LunarConcept.Tools;
using SHomeWorkshop.LunarConcept.Enums;

namespace SHomeWorkshop.LunarConcept.Commands
{
    /// <summary>
    /// 创建时间：2012年12月31日
    /// 创建者：  杨震宇
    /// 
    /// 主要用途：设置直线部件作连接线时尾端点指向目标部件哪个锚定位置。
    /// ★★说明：关于自定义命令的实现，可参考“NewDocument”类的备注。
    /// </summary>
    public static class SetEndLinkToCommand
    {
        #region 构造方法=====================================================================================================

        /// <summary>
        /// ★②，修改静态构造方法名。
        /// </summary>
        static SetEndLinkToCommand()//类型构造器
        {
            //★③，修改两个字符串参数名。★④以及第三个参数的类型名。
            routedUICmd = new RoutedUICommand(
                "SetEndLinkToCommand",
                "SetEndLinkToCommand",
                typeof(SetEndLinkToCommand),//创建RoutedUICommand对象
                null);

            //如果需要挂接快捷键，请参考下面这段代码：
            //routedUICmd = new RoutedUICommand(
            //    "SaveDocumentCommand",
            //    "SaveDocumentCommand",
            //    typeof(SaveDocumentCommand),//创建RoutedUICommand对象
            //    new InputGestureCollection() 
            //    { 
            //        //★⑤，修改此处三个参数，以便挂接快捷键。
            //        new KeyGesture(Key.S,ModifierKeys.Control,"Ctrl+S")
            //    });

            cmdBinding.Command = routedUICmd;
            cmdBinding.CanExecute += new CanExecuteRoutedEventHandler(cmdBinding_CanExecute);
            cmdBinding.Executed += new ExecutedRoutedEventHandler(cmdBinding_Executed);
        }

        #endregion

        #region 字段与属性===================================================================================================

        private static CommandBinding cmdBinding = new CommandBinding();
        /// <summary>
        /// 用在主窗口CommandBindings集合中的命令绑定。
        /// 
        /// 它的Command是RoutedUICommand。
        /// ——因此，RoutedUICommand是否可以运行将由CmdBinding的CanExecute事件决定。
        /// ——而且，RoutedUICommand的执行也是通过CmdBinding的Execute事件来进行的。
        /// </summary>
        public static CommandBinding CmdBinding
        {
            get { return cmdBinding; }
        }

        private static RoutedUICommand routedUICmd;
        /// <summary>
        /// [只读静态属性]表示在WPF系统中注册的一个RoutedUICommand。
        /// ——必须和CommandBinding配合才能使用。
        ///     CommandBinding要添加到主窗口的CommandBindings集合中；
        ///     RoutedUICommand则要向WPF系统注册。
        ///     
        /// ★说明：使用静态属性是因为这样在Xaml代码中比较便于绑定。
        /// </summary>
        public static RoutedUICommand RoutedUICmd
        {
            get { return routedUICmd; }
        }

        #endregion

        #region 方法=========================================================================================================

        static void cmdBinding_CanExecute(object sender, CanExecuteRoutedEventArgs e)
        {
            //★⑧，修改此方法的实现。
            //if (Globals.MainWindow == null)
            //{
            //    e.CanExecute = false; return;
            //}

            //EditorManager manager = Globals.MainWindow.EditorManager;

            //if (manager == null)
            //{
            //    e.CanExecute = false; return;
            //}

            //List<Widgets.Widget> selectedWidgets = manager.GetSelectedWidgetsList();

            //if (selectedWidgets.Count <= 0)
            //{
            //    e.CanExecute = false; return;
            //}

            //int arrowLineCount = 0;
            //foreach (Widgets.Widget w in selectedWidgets)
            //{
            //    if (w is Widgets.ArrowLineWidget) arrowLineCount++;
            //}

            //if (arrowLineCount <= 0)
            //{
            //    e.CanExecute = false; return;
            //}

            e.CanExecute = true; return;
        }

        static void cmdBinding_Executed(object sender, ExecutedRoutedEventArgs e)
        {
            //★⑦，修改此方法的实现。

            try
            {
                LinkToPoint newLinkTo = (LinkToPoint)Enum.Parse(typeof(LinkToPoint), e.Parameter as string);
                LunarMessage.Warning(Execute(newLinkTo));
            }
            catch (Exception ex)
            {
                LunarMessage.Warning(ex.Message);
            }
        }

        /// <summary>
        /// [公开静态方法]即使此命令处于禁用状态，也可以通过代码调用此方法来执行特定任务！！！
        /// 
        /// 当被绑定的命令被调用（触发）时，会引发cmdBinding_Executed事件。
        /// 在cmdBinding_Executed事件处理器方法中已添加了调用Execute()方法的代码。
        /// 
        /// ——因此，触发命令，就相当于调用此方法！！！
        /// </summary>
        public static string Execute(Enums.LinkToPoint newLinkToPoint)
        {
            if (Globals.MainWindow == null) return "　　未找到Globals.MainWindow。";
            EditorManager manager = Globals.MainWindow.EditorManager;
            if (manager == null) return "　　未找到页面管理器。";

            List<Widgets.Widget> selectedWidgets = manager.GetSelectedWidgetsList();
            if (selectedWidgets.Count <= 0) return "　　未选定任何部件。";

            ModifingInfo info = new ModifingInfo();
            info.ModifingDescription = "设置直线尾端点锚定位置";
            manager.GetSelectedPageEditorStatus(info);
            manager.GetSelectedWidgetStatus_Old(info);
            manager.GetSelectedWidgetStatus_New(info);

            ModifingItem<Action, ModifingInfo> mi = new ModifingItem<Action, ModifingInfo>(info);

            int linkedStraitLinesCount = 0;

            foreach (Widgets.Widget w in selectedWidgets)
            {
                Widgets.StraitLineWidget slw = w as Widgets.StraitLineWidget;
                if (slw != null && slw.IsLinked)
                {
                    if (slw.EndLinkTo == newLinkToPoint) continue;//不需要改，跳过。

                    if (slw.MasterEditor != null)
                    {
                        Widgets.Widget masterStartWidget = slw.MasterEditor.GetWidget(slw.StartMasterId);
                        Widgets.Widget masterEndWidget = slw.MasterEditor.GetWidget(slw.EndMasterId);
                        if (masterStartWidget != null && masterEndWidget != null)
                        {
                            Rect startRect = masterStartWidget.OuterRect;
                            Rect endRect = masterEndWidget.OuterRect;
                            startRect.X -= 4; startRect.Y -= 4; startRect.Width += 8; startRect.Height += 8;
                            endRect.X -= 4; endRect.Y -= 4; endRect.Width += 8; endRect.Height += 8;

                            Point startCenter = new Point(startRect.Left + startRect.Width / 2, startRect.Top + startRect.Height / 2);
                            Point endCenter = new Point(endRect.Left + endRect.Width / 2, endRect.Top + endRect.Height / 2);

                            //重新计算两点坐标才成。
                            if (slw.StartLinkTo == LinkToPoint.Center && newLinkToPoint == LinkToPoint.Center)
                            {
                                #region 如果 首、尾 端点均指向中心
                                PointToRect.ArrowPoints aptStart = PointToRect.GetCrossPointToRect(startRect, endCenter);
                                PointToRect.ArrowPoints aptEnd = PointToRect.GetCrossPointToRect(endRect, startCenter);

                                Action actSetStartPoint = new Action(w.MasterEditor.Id, w.Id, w.GetType().Name, XmlTags.StartPointTag,
                                                                slw.StartPoint.ToString(), aptStart.Top.ToString());
                                slw.StartPoint = aptStart.Top;
                                mi.AddAction(actSetStartPoint);

                                Action actSetEndPoint = new Action(w.MasterEditor.Id, w.Id, w.GetType().Name, XmlTags.EndPointTag,
                                                                slw.EndPoint.ToString(), aptEnd.Top.ToString());
                                slw.EndPoint = aptEnd.Top;
                                mi.AddAction(actSetEndPoint);
                                #endregion
                            }
                            else
                            {
                                if (slw.StartLinkTo == LinkToPoint.Center)
                                {
                                    #region 如果 首端点 指向中心，尾端点不是指向中心
                                    Point? newEnd = slw.GetLinkedPoint(endRect, newLinkToPoint);

                                    if (newEnd == null || newEnd.HasValue)
                                    {
                                        //首端点指向中心，尾端点指向边框
                                        //尾端点指向边框上某个不确定的点  newLinkToPoint == LinkToPoint.Border
                                        //尾端点由首端点相对于尾部件矩形的位置决定。
                                        //switch (Globals.GetLocationArea(endRect, startCenter))
                                        switch(newLinkToPoint)
                                        {
                                            case Enums.LinkToPoint.Left:
                                                newEnd = new Point(endRect.X, endCenter.Y);
                                                break;
                                            case Enums.LinkToPoint.TopLeft:
                                                newEnd = endRect.TopLeft;
                                                break;
                                            case Enums.LinkToPoint.Top:
                                                newEnd = new Point(endCenter.X, endRect.Y);
                                                break;
                                            case Enums.LinkToPoint.TopRight:
                                                newEnd = endRect.TopRight;
                                                break;
                                            case Enums.LinkToPoint.Right:
                                                newEnd = new Point(endRect.X + endRect.Width, endCenter.Y);
                                                break;
                                            case Enums.LinkToPoint.BottomRight:
                                                newEnd = endRect.BottomRight;
                                                break;
                                            case Enums.LinkToPoint.Bottom:
                                                newEnd = new Point(endCenter.X, endRect.Bottom);
                                                break;
                                            case Enums.LinkToPoint.BottomLeft:
                                                newEnd = endRect.BottomLeft;
                                                break;
                                            //case LocationArea.Center:
                                            default:
                                                newEnd = endCenter;
                                                break;
                                        }
                                    }//else 首端点指向中心，尾端点在边框上八点之一，不变。

                                    PointToRect.ArrowPoints aptStart = PointToRect.GetCrossPointToRect(startRect, newEnd.Value);
                                    Action actSetStartPoint = new Action(w.MasterEditor.Id, w.Id, w.GetType().Name, XmlTags.StartPointTag, slw.StartPoint.ToString(), aptStart.Top.ToString());
                                    slw.StartPoint = aptStart.Top;
                                    mi.AddAction(actSetStartPoint);

                                    Action actSetEndPoint = new Action(w.MasterEditor.Id, w.Id, w.GetType().Name, XmlTags.EndPointTag,
                                                                    slw.EndPoint.ToString(), newEnd.Value.ToString());
                                    slw.EndPoint = newEnd.Value;
                                    mi.AddAction(actSetEndPoint);

                                    #endregion
                                }
                                else if (newLinkToPoint == LinkToPoint.Center)
                                {
                                    #region 如果 首端点 是边框上八点之一，尾端点指向中心
                                    Point? newStart = slw.GetLinkedPoint(startRect, newLinkToPoint);
                                    if (newStart != null && newStart.HasValue)
                                    {
                                        PointToRect.ArrowPoints aptEnd = PointToRect.GetCrossPointToRect(endRect, newStart.Value);

                                        Action actSetStartPoint = new Action(w.MasterEditor.Id, w.Id, w.GetType().Name, XmlTags.StartPointTag,
                                                                slw.StartPoint.ToString(), newStart.Value.ToString());
                                        slw.StartPoint = newStart.Value;
                                        mi.AddAction(actSetStartPoint);

                                        Action actSetEndPoint = new Action(w.MasterEditor.Id, w.Id, w.GetType().Name, XmlTags.EndPointTag,
                                                                        slw.EndPoint.ToString(), aptEnd.Top.ToString());
                                        slw.EndPoint = aptEnd.Top;
                                        mi.AddAction(actSetEndPoint);
                                    }
                                    #endregion
                                }
                                else
                                {
                                    #region 首端点不指向中心，尾端点也不指向中心
                                    Point? newStart = slw.GetLinkedPoint(startRect, slw.StartLinkTo);
                                    Point? newEnd = slw.GetLinkedPoint(endRect, newLinkToPoint);
                                    if (newStart != null && newStart.HasValue)
                                    {
                                        if (newEnd == null || newEnd.HasValue)
                                        {
                                            //首端点不指向中心，尾端点指向边框。
                                            switch (Globals.GetLocationArea(endRect, newStart.Value))
                                            {
                                                case LocationArea.Left:
                                                    newEnd = new Point(endRect.X, newStart.Value.Y);
                                                    break;
                                                case LocationArea.LeftTop:
                                                    newEnd = endRect.TopLeft;
                                                    break;
                                                case LocationArea.Top:
                                                    newEnd = new Point(newStart.Value.X, endRect.Y);
                                                    break;
                                                case LocationArea.RightTop:
                                                    newEnd = endRect.TopRight;
                                                    break;
                                                case LocationArea.Right:
                                                    newEnd = new Point(endRect.X + endRect.Width, newStart.Value.Y);
                                                    break;
                                                case LocationArea.RightBottom:
                                                    newEnd = endRect.BottomRight;
                                                    break;
                                                case LocationArea.Bottom:
                                                    newEnd = new Point(newStart.Value.X, endRect.Bottom);
                                                    break;
                                                case LocationArea.LeftBottom:
                                                    newEnd = endRect.BottomLeft;
                                                    break;
                                                //case LocationArea.Center:
                                                default:
                                                    newEnd = endCenter;
                                                    break;
                                            }
                                        }//else 首端点不指向中心，尾端点指向边框八点之一，不变

                                        Action actSetStartPoint = new Action(w.MasterEditor.Id, w.Id, w.GetType().Name, XmlTags.StartPointTag,
                                                                slw.StartPoint.ToString(), newStart.Value.ToString());
                                        slw.StartPoint = newStart.Value;
                                        mi.AddAction(actSetStartPoint);
                                        Action actSetEndPoint = new Action(w.MasterEditor.Id, w.Id, w.GetType().Name, XmlTags.EndPointTag,
                                                                        slw.EndPoint.ToString(), newEnd.Value.ToString());
                                        slw.EndPoint = newEnd.Value;
                                        mi.AddAction(actSetEndPoint);
                                    }
                                    #endregion
                                }
                            }
                        }
                    }

                    Action actSetEndLinkToCommand = new Action(w.MasterEditor.Id, w.Id, w.GetType().Name, XmlTags.EndLinkToTag,
                    slw.EndLinkTo.ToString(), newLinkToPoint.ToString());
                    slw.EndLinkTo = newLinkToPoint;
                    mi.AddAction(actSetEndLinkToCommand);

                    linkedStraitLinesCount++;

                    continue;
                }
            }

            if (linkedStraitLinesCount <= 0) return "　　未选定任何作连接线的直线，或者指定的锚定位置与原锚定位置相同！";

            manager.RegisterModifingItem(mi);
            return string.Empty;
        }
        #endregion
    }
}
